package com.example.myanimator.circleanimator

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.view.animation.LinearInterpolator
import androidx.annotation.IntDef
import com.example.myanimator.R
import com.example.myanimator.utils.ScreenUtils
import com.example.myanimator.utils.TimeFormatUtils
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlin.coroutines.CoroutineContext


/**
 * @author tgw
 * @date 2021/12/10
 * @describe 倒计时圆动画
 *
 * 还有一种思路根据定时，计算已运行时间在360的总周期占多少，根据数据去绘制动画效果
 *
 *外部关注该方法
 * setCircleStyleStart（）
 */
/**
 * @author tgw
 * @date 2021/12/10
 * @describe 倒计时圆动画--
 */
class CircleAnimatorViewFinish(context: Context, attrs: AttributeSet?) : View(context, attrs),
    CoroutineScope {


    override val coroutineContext: CoroutineContext
        get() = Job() + Dispatchers.Main

    companion object {
        private const val TAG = "CircleAnimatorView"


        fun dip2px(context: Context, dpValue: Float): Float {
            val scale = context.resources.displayMetrics.density
            return dpValue * scale + 0.5f
        }

        /**
         * 定义几个圆圈类型的常量
         *  动画类型，1 未开始，2进行中，3已结束
         */
//        private const val STYLE_TYPE_NOT_START = 1
//        private const val STYLE_TYPE_RUNNING = 2
//        private const val STYLE_TYPE_END = 3
    }

    private lateinit var mAnimaPath: Path
    private lateinit var mDstPath: Path
    private var circleValueAnimator: ValueAnimator? = null
    private var mPaint: Paint
    private var mPaintBg: Paint
    private var mTextPaint: Paint

    //运行中特有画笔，文字要小
    private var mTextRunningHintPaint: Paint

    //整个控件的大小范围 也是圆的范围，也是文字的范围
    private var circleRectF: RectF? = null
    private var mPathMeasure: PathMeasure? = null

    //动画进度
    private var mCurAnimValue = 0f
    private var endLength = 0f
    private var mProgressWidth = 0f
    private var mCircleRadius = 0f

    //画笔颜色
    private var mBgColor = Color.parseColor("#FF1FB5AB")
    private var mProgressBgColor = Color.parseColor("#FFEFEFEF")
    private var mRunningHintTextColor = Color.parseColor("#FF999999")

    //控件大小
    private var mViewHeight = 0
    private var mViewWidth = 0

    //控件中心点
    private var mViewWidthCenterX = 0F
    private var mViewHeightCenterY = 0F

    //2进行中 动画圆倒计时,计算已运行的长度
    private var runningDurationLength: Float = 0f

    //动画类型，1 未开始，2进行中，3已结束
    private var mCircleStyleType:CircleAnimatorViewStyleType = CircleAnimatorViewStyleType.STYLE_TYPE_NOT_START

    //课堂开始时间
    private var mCircleStartTime = 0L

    //课堂结束时间
    private var mCircleEndTime = 0L

    //动画类型，1 未开始，3已结束的文案与居中基准线
    private var mHintTextSize = 36f
    private var mHintText = ""
    private var mCenterBaseline: Float? = 0f

    //动画类型，进行中
    private var mRunningRemainTime = 0L //相当于倒计时
    private var mRunningTimeHintText = ""
    private var mRunningTimeHintTextDistance = 0f  //文本相距距离
    private var mRunningHintText = "距离结束"

    //协程流
    private var mRunningFlowJob: Job? = null  //进行中的倒计时文案
    private var mStartTimeFlowJob: Job? = null //未开始，到时间后转化为进行中

    //已结束的回调监听
    var mObserverAnimatorEndListener: (() -> Unit)? = null

    init {
        setLayerType(LAYER_TYPE_SOFTWARE, null)
        if (attrs != null) {
            val typedArray =
                getContext().obtainStyledAttributes(attrs, R.styleable.CircleAnimatorView)
            mBgColor = typedArray.getColor(R.styleable.CircleAnimatorView_bgColor, mBgColor)
            mProgressBgColor = typedArray.getColor(
                R.styleable.CircleAnimatorView_animationProgressColor,
                mProgressBgColor
            )
            mProgressWidth = dip2px(
                context,
                typedArray.getDimension(
                    R.styleable.CircleAnimatorView_progressWidth,
                    mProgressWidth
                )
            )
            mCircleRadius =
            dip2px(
                    context, typedArray.getDimension(
                        R.styleable.CircleAnimatorView_circleRadius,
                        mCircleRadius
                    )
                )

            mHintTextSize = dip2px(
                context, typedArray.getDimension(
                    R.styleable.CircleAnimatorView_circleTextHintSize, mHintTextSize
                )
            )

            typedArray.recycle()
        }
        //相当于蓝色圆圈覆盖灰色圆圈,然后蓝色圈圈慢慢消散
        mPaint = Paint()
        mPaint.isAntiAlias = true // 去除锯齿
        mPaint.strokeWidth = mProgressWidth
        mPaint.style = Paint.Style.STROKE
        mPaint.color = mProgressBgColor
        //相当于蓝色圆圈
        mPaintBg = Paint()
        mPaintBg.isAntiAlias = true // 去除锯齿
        mPaintBg.strokeWidth = mProgressWidth - 2
        mPaintBg.style = Paint.Style.STROKE
        mPaintBg.color = mBgColor
        mPaintBg.strokeCap = Paint.Cap.ROUND

        mTextPaint = Paint() // 创建每个模式都有的文字画笔
        mTextPaint.color = Color.BLACK // 设置颜色
        mTextPaint.isAntiAlias = true // 去除锯齿
        mTextPaint.style = Paint.Style.FILL // 设置样式
        mTextPaint.textSize = mHintTextSize // 设置字体大小
        mTextPaint.textAlign = Paint.Align.CENTER

        //距离课堂结束文案的文字画笔
        mTextRunningHintPaint = Paint() // 创建每个模式都有的文字画笔
        mTextRunningHintPaint.color = mRunningHintTextColor // 设置颜色
        mTextRunningHintPaint.isAntiAlias = true // 去除锯齿
        mTextRunningHintPaint.style = Paint.Style.FILL // 设置样式
        mTextRunningHintPaint.textSize = ScreenUtils.dip2px(context, 24f) // 设置字体大小
        mTextRunningHintPaint.textAlign = Paint.Align.CENTER
    }


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        mViewWidth = measureWidthOrHeight(widthMeasureSpec)
        mViewHeight = measureWidthOrHeight(heightMeasureSpec)
        setMeasuredDimension(mViewWidth, mViewHeight)
        init()
    }

    private fun measureWidthOrHeight(measureSpec: Int): Int {
        var result = 0
        //获取当前View的测量模式
        val mode = MeasureSpec.getMode(measureSpec)
        //精准模式获取当前Viwe测量后的值,如果是最大值模式,会获取父View的大小.
        val size = MeasureSpec.getSize(measureSpec)
        if (mode == MeasureSpec.EXACTLY) {
            //当测量模式为精准模式,返回设定的值
            result = size
        } else {
            //设置为WrapContent的默认大小,圆的直径加上画笔宽度
            result = (mCircleRadius * 2 + mProgressWidth).toInt()
            if (mode == MeasureSpec.AT_MOST) {
                //当模式为最大值的时候,默认大小和父类View的大小进行对比,返回最小的值
                result = Math.min(result, size)
            }
        }
        return result
    }

    private fun init() {
        val path = mCircleRadius * 2
        val left = (mViewWidth - mCircleRadius * 2) / 2
        val top = (mViewHeight - mCircleRadius * 2) / 2
        mViewWidthCenterX = (mViewWidth / 2).toFloat()
        mViewHeightCenterY = (mViewHeight / 2).toFloat()
        //画圆
        circleRectF = RectF(left, top, path + left, path + top)
        mAnimaPath = Path()
        mDstPath = Path()
//        mAnimaPath.addArc(circleRectF, -90f, 359f)
        mAnimaPath.arcTo(circleRectF!!, -90f, 359f, true)
        mPathMeasure = PathMeasure(mAnimaPath, true)

        //画居中文本，计算基准线
        // 参数分别为 (文本 基线x 基线y 画笔),根据中心点以及文本基准线调整文本的中心
        val fontMetrics: Paint.FontMetrics = mTextPaint.fontMetrics
        val distance = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom
        mCenterBaseline = circleRectF?.centerY()?.plus(distance)

        //运行时 两行文本相距距离
        mRunningTimeHintTextDistance = ScreenUtils.dip2px(context, 30f)
    }

    /**根据课程时段自动选择动画类型*/
    fun setCircleStyleStart(
        startTime: Long,
        endTime: Long
    ) {
        mCircleStartTime = startTime
        mCircleEndTime = endTime

        val currentTime = System.currentTimeMillis()
        when {
            currentTime < startTime -> {
                setCircleStyleTypeNotStart(startTime, endTime)
            }
            currentTime in startTime until endTime -> {
                setCircleStyleTypeRunning(startTime, endTime)
            }
            currentTime >= endTime -> {
                setCircleStyleTypeEnd(startTime, endTime)
            }
        }
    }

    /**未开始*/
    private fun setCircleStyleTypeNotStart(startTime: Long, endTime: Long) {
        val currentTime = System.currentTimeMillis()
        if (currentTime < startTime) {
            setCircleCircleStyleType(CircleAnimatorViewStyleType.STYLE_TYPE_NOT_START, startTime, endTime)
        }
    }

    /**进行中*/
    private fun setCircleStyleTypeRunning(
        startTime: Long, endTime: Long
    ) {
        setCircleCircleStyleType(CircleAnimatorViewStyleType.STYLE_TYPE_RUNNING, startTime, endTime)
//        LogUtil.d(
//            TAG,
//            "setCircleStyleTypeRunning:周期： ${endTime - startTime}，已运行周期${System.currentTimeMillis() - startTime}"
//        )
        setCircleValueAnimatorStart(
            startTime,
            endTime,
            endTime - startTime,
            System.currentTimeMillis() - startTime
        )
    }

    /**已结束*/
    private fun setCircleStyleTypeEnd(startTime: Long, endTime: Long) {
        val currentTime = System.currentTimeMillis()
        if (currentTime >= endTime) {
            setCircleCircleStyleType(CircleAnimatorViewStyleType.STYLE_TYPE_END, startTime, endTime)
        }
    }


    /**
     *
     * 该方法只有 mCircleStyleType == 2时才会生效
     *@param duration  总周期
     *@param runningDuration 已运行周期
     */
    private fun setCircleValueAnimatorStart(
        startTime: Long, endTime: Long,
        duration: Long,
        runningDuration: Long
    ) {
        if (mCircleStyleType == CircleAnimatorViewStyleType.STYLE_TYPE_RUNNING) {
            if (runningDuration >= duration) {
                setCircleStyleTypeEnd(startTime, endTime)
                return
            }
            //防止同样大小，覆盖的不全
            mPaintBg.strokeWidth = mProgressWidth - 2
            setAnimator(duration, runningDuration)
        }
    }


    /**
     *设置圆圈展示的样式
     */
    private fun setCircleCircleStyleType(circleStyleType: CircleAnimatorViewStyleType, startTime: Long, endTime: Long) {
        mCircleStyleType = circleStyleType
        Log.e(TAG, "setCircleCircleStyleType type $circleStyleType")
        when (mCircleStyleType) {
            CircleAnimatorViewStyleType.STYLE_TYPE_NOT_START -> {
                mHintText = "未开始"
                setStartTimeJobCollect(startTime, endTime)
            }
            CircleAnimatorViewStyleType.STYLE_TYPE_END -> {
                mHintText = "已结束"
                mObserverAnimatorEndListener?.invoke()
            }
        }
        //防止之前是模式二 有动画
        circleValueAnimator?.cancel()
        mRunningFlowJob?.cancel()
        mPaintBg.strokeWidth = mProgressWidth
        postInvalidate()
    }

    /**进入时是未开始 课程到开始时间后 自动ui调整*/
    private fun setStartTimeJobCollect(startTime: Long, endTime: Long) {
        mStartTimeFlowJob?.cancel()
        /**辅助进入的时候为未开始，到了时间点将为开始*/
        val countDownStartTimeFlow = flow<Boolean> {
            while (mCircleStyleType == CircleAnimatorViewStyleType.STYLE_TYPE_NOT_START) {
                delay(1000)
                if (System.currentTimeMillis() > startTime) {
                    emit(true)
                } else {
                    emit(false)
                }
            }
        }.flowOn(Dispatchers.IO)
        mStartTimeFlowJob = launch(Dispatchers.Main) {
            countDownStartTimeFlow.collect {
                if (it) {
                    setCircleStyleTypeRunning(startTime, endTime)
                    mStartTimeFlowJob?.cancel()
                }
            }
        }
    }

    private fun setAnimator(
        duration: Long,
        runningDuration: Long
    ) {
        if (mPathMeasure == null) {
            init()
        }
        //倒计时时间与文案,计算剩余时间
        mRunningRemainTime =
            (mCircleEndTime - mCircleStartTime) - (System.currentTimeMillis() - mCircleStartTime)

        mRunningTimeHintText = TimeFormatUtils.secToTime(mRunningRemainTime.toInt() / 1000)
        //收集倒计时的文本
        setRunningTextJobCollect()

        var runningProgress = 0f
        if (runningDuration <= 0) {
            runningDurationLength = mPathMeasure!!.length
        } else {
            //动画圆倒计时,计算已运行的长度
            runningDurationLength = runningDuration / duration * mPathMeasure!!.length
            runningProgress = (runningDuration.toFloat() / duration.toFloat()).toFloat()
        }
        circleValueAnimator = ValueAnimator.ofFloat(0f, 1f)
        circleValueAnimator?.let { circleValueAnimator ->
            circleValueAnimator.repeatCount = 0
            circleValueAnimator.duration = duration.toLong()
            circleValueAnimator.interpolator = LinearInterpolator()
            circleValueAnimator.addUpdateListener { animation ->
                mCurAnimValue = (animation.animatedValue as Float) + runningProgress
                if (mCurAnimValue <= 1f) {
                    postInvalidate()
                } else {
                    circleValueAnimator.cancel()
                }
            }
            circleValueAnimator.addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator) {
                    super.onAnimationEnd(animation)
                    setCircleStyleTypeEnd(mCircleStartTime, mCircleEndTime)
                }
            })
            //防止android 5.0 属性动画失效
            ValueAnimatorUtil.resetDurationScaleIfDisable()
            circleValueAnimator.start()
        }


    }


    /**
     *运行时动画的倒计时文案
     */
    private fun setRunningTextJobCollect() {
        mRunningFlowJob?.cancel()
        var time = 0
        val countDownRunningStyleTextHint = flow<String> {
            while (mCircleStyleType == CircleAnimatorViewStyleType.STYLE_TYPE_RUNNING) {
                delay(500)
                mRunningRemainTime =
                    (mCircleEndTime - mCircleStartTime) - (System.currentTimeMillis() - mCircleStartTime)
                time = mRunningRemainTime.toInt() / 1000
                emit(TimeFormatUtils.secToTime(time))
            }
        }.flowOn(Dispatchers.IO)
        mRunningFlowJob = launch {
            countDownRunningStyleTextHint.collect {
                mRunningTimeHintText = it
            }
        }
    }


    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        when (mCircleStyleType) {
            CircleAnimatorViewStyleType.STYLE_TYPE_NOT_START -> {
                // 参数分别为 (文本 基线x 基线y 画笔),根据中心点以及文本基准线调整文本的中心
                mCenterBaseline?.let {
                    canvas.drawText(
                        mHintText, mViewWidthCenterX,
                        it, mTextPaint
                    )
                }
                canvas.drawCircle(
                    mViewWidthCenterX,
                    mViewHeightCenterY, mCircleRadius, mPaintBg
                )
            }
            CircleAnimatorViewStyleType.STYLE_TYPE_RUNNING -> {
                // 参数分别为 (文本 基线x 基线y 画笔),根据中心点以及文本基准线调整文本的中心
                mCenterBaseline?.let {
                    canvas.drawText(
                        mRunningTimeHintText, mViewWidthCenterX.toFloat(),
                        it - mRunningTimeHintTextDistance, mTextPaint
                    )
                    canvas.drawText(
                        mRunningHintText, mViewWidthCenterX.toFloat(),
                        it + mRunningTimeHintTextDistance, mTextRunningHintPaint
                    )
                }
                canvas.drawPath(mAnimaPath, mPaint)
                drawAnimationCircle(canvas)
            }
            CircleAnimatorViewStyleType.STYLE_TYPE_END -> {
                // 参数分别为 (文本 基线x 基线y 画笔),根据中心点以及文本基准线调整文本的中心
                mCenterBaseline?.let {
                    canvas.drawText(
                        mHintText, mViewWidthCenterX,
                        it, mTextPaint
                    )
                }
                canvas.drawCircle(
                    mViewWidthCenterX,
                    mViewHeightCenterY, mCircleRadius, mPaint
                )
            }

        }
    }

    /**先覆盖蓝色圈然后，慢慢褪去，顺时针画的圆弧，利用mPathMeasure 倒退绘制，模拟逆时针*/
    private fun drawAnimationCircle(canvas: Canvas) {
        if (mPathMeasure == null) {
            return
        }
        endLength = (mPathMeasure!!.length * (1 - mCurAnimValue))
        mDstPath.reset()
//        LogUtil.d(
//            TAG,
//            "drawAnimationCircle-endLength: " + endLength + "圆绘制 动画进度" + mCurAnimValue + "mPathMeasurelength:" + mPathMeasure!!.getLength()
//        )
        mPathMeasure!!.getSegment(0f, endLength, mDstPath, true)
        canvas.drawPath(mDstPath, mPaintBg)
    }


    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        onDestroy()
    }

    fun onDestroy() {
        mRunningFlowJob?.cancel()
        mStartTimeFlowJob?.cancel()
        circleValueAnimator?.cancel()
        coroutineContext.cancel()
        mObserverAnimatorEndListener = null
    }

    enum class CircleAnimatorViewStyleType{
        //未开始
        STYLE_TYPE_NOT_START ,
        //进行中
        STYLE_TYPE_RUNNING ,
        //已结束
        STYLE_TYPE_END ,
    }


//    fun aa(@CircleAnimatorViewStyleType type:Int){
//
//    }
//
//    /**
//     * 动画类型，1 未开始，2进行中，3已结束
//     */
//    @Target(AnnotationTarget.VALUE_PARAMETER)
//    @IntDef(
//        CircleAnimatorViewStyleType.STYLE_TYPE_NOT_START,
//        CircleAnimatorViewStyleType.STYLE_TYPE_RUNNING,
//        CircleAnimatorViewStyleType.STYLE_TYPE_END
//    )
//    @Retention(AnnotationRetention.SOURCE)
//    annotation class CircleAnimatorViewStyleType {
//        companion object {
//            /**
//             * 定义几个圆圈类型的常量
//             *  动画类型，1 未开始，2进行中，3已结束
//             */
//            const val STYLE_TYPE_NOT_START = 1
//            const val STYLE_TYPE_RUNNING = 2
//            const val STYLE_TYPE_END = 3
//        }
//    }


}
